#include "pcap-ipv4.h"
#include "appender.h"
#include <QDebug>

CPCapIpv4Packet::CPCapIpv4Packet(QObject *parent) :
    CPCapPacket(parent)
{

}

CPCapIpv4Packet::~CPCapIpv4Packet()
{

}

QString CPCapIpv4Packet::ttl() const
{
    return m_ttl;
}

void CPCapIpv4Packet::setTTL(const QString &ttl)
{
    m_ttl = ttl;
    emit ttlChanged();
}

QString CPCapIpv4Packet::protocol() const
{
    return m_protocol;
}

void CPCapIpv4Packet::setProtocol(const QString &protocol)
{
    m_protocol = protocol;
    emit protocolChanged();
}

QString CPCapIpv4Packet::sourceIp() const
{
    return m_sourceIp;
}

void CPCapIpv4Packet::setSourceIp(const QString &sourceIp)
{
    m_sourceIp = sourceIp;
    emit sourceIpChanged();
}

QString CPCapIpv4Packet::destIp() const
{
    return m_destIp;
}

void CPCapIpv4Packet::setDestIp(const QString &destIp)
{
    m_destIp = destIp;
    emit destIpChanged();
}

int CPCapIpv4Packet::headerLength()
{
    return 20;
}

bool CPCapIpv4Packet::buildHeader(QByteArray &header)
{
    if (m_ttl.isEmpty()) {
        m_ttl = "64";
    }
    if (m_protocol.isEmpty()) {
        m_protocol = "0";
    }
    if (m_destIp.isEmpty()) {
        m_destIp = "127.0.0.1";
    }
    if (m_sourceIp.isEmpty()) {
        m_sourceIp = "127.0.0.2";
    }

    CAppender apd(&header);
    //version (high 4 bits) + header length (low 4 bits)
    if (!apd.appendBin("01000101")) {
        qCritical() << "IPv4: append version failed";
        return false;
    }
    //differentiated services field (1 byte)
    if (!apd.appendBin("00000000")) {
        qCritical() << "IPv4: append DSF failed";
        return false;
    }
    //total length int bytes including header (2 bytes)
    quint16 totalLength = (20 + payloadLength());
    if (!apd.appendUInt16(totalLength)) {
        qCritical() << "IPv4: append total length failed: " << totalLength;
        return false;
    }
    //unique identification of packet (2 bytes)
    if (!apd.appendBin("0000000000000000")) {
        qCritical() << "IPv4: append identification failed";
        return false;
    }
    //flags: 0-DF-MF (3 bits)
    //flags: fragment offset in 64 bit blocks (13 bits)
    if (!apd.appendBin("0000000000000000")) {
        qCritical() << "IPv4: append flags failed";
        return false;
    }
    //time to live (1 byte)
    if (!apd.appendUInt8(m_ttl)) {
        qCritical() << "IPv4: append ttl failed: " << m_ttl;
        return false;
    }
    //protocol (1 byte)
    if (!apd.appendUInt8(m_protocol)) {
        qCritical() << "IPv4: append protocol failed: " << m_protocol;
        return false;
    }
    //header checksum (2 bytes)
    if (!apd.appendBin("0000000000000000")) {
        qCritical() << "IPv4: append checksum failed";
        return false;
    }
    //source address
    if (!apd.appendSepDec(m_sourceIp, ".", 4)) {
        qCritical() << "IPv4: append src addr failed: " << m_sourceIp;
        return false;
    }
    //destination address
    if (!apd.appendSepDec(m_destIp, ".", 4)) {
        qCritical() << "IPv4: append dst addr failed: " << m_destIp;
        return false;
    }
    return true;
}
